#include <windows.h>
#include <stdio.h>
#include <string.h>
#include "..\Comun\Transferencia.c"
#include "..\Comun\Parser.c"

#define RES_ERROR_PORT_TYPE -2
#define RES_ERROR_COMMAND_LINE -3
#define RES_OK 0
#define RES_ERROR -1
#define RES_ERROR_PORT_RANGE -4

DWORD WINAPI DataReceiverThread (LPVOID lpParameter);
DWORD WINAPI DataSenderThread(LPVOID lpParameter);

HANDLE serverDataReceiverThread;
HANDLE serverDataSenderThread;

DWORD  receiverThreadName;
DWORD senderThreadName;

int closeThread = 0;

int parseCommandLine(int argc, char* argv[], int *port);

int main (int argc, char*argv[]){
	
	int port;
	int error = 0;
	WSADATA wsaData; //es necesario para la compilacion de sockets en V6.0
	CONEXION conexion;

	
	if(parseCommandLine(argc,argv,&port)!=RES_OK)
		return RES_ERROR;

	printf(">>Escuchando conexiones en el puerto: %d\n",port);
	while (closeThread == 0)
	{	

		if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) { // es necesario para la inicializacon de la dll WINSOCK32 
			exit(1);
		}

		error =  trEscuchar(port, &conexion);

		if (error == 0)	{
			  	
			  serverDataReceiverThread = CreateThread( 
				NULL,                   // default security attributes
				0,                      // use default stack size  
				DataReceiverThread,       // thread function name
				(LPVOID)&conexion,          // argument to thread function 
				0,                      // use default creation flags 
				&receiverThreadName);   // returns the thread identifier */

			  serverDataSenderThread = CreateThread( 
				NULL,                   // default security attributes
				0,                      // use default stack size  
				DataSenderThread,       // thread function name
				(LPVOID)&conexion,          // argument to thread function 
				0,                      // use default creation flags 
				&senderThreadName);   // returns the thread identifier 

			  WaitForSingleObject(serverDataReceiverThread, INFINITE);
			  //WaitForSingleObject(serverDataSenderThread, INFINITE);
		  			  
		}
		
		else{
			//ToDo: Identificar error y mostrarlo por pantalla
		}
	}
	return 0;
}


DWORD WINAPI DataReceiverThread (LPVOID lpParameter){

	char datos[500];
	int cantItems;
	int type = -2;

	CONEXION *pConexion = (CONEXION*)lpParameter;
	
	int message = DataReceiver(pConexion, &datos,  &cantItems, &type);

	switch (message)
	{
		case RES_QUIT: 
		{					
			printf("Se ha terminado el programa del lado del cliente. Presione enter para continuar o quit para salir.\n");
			WaitForSingleObject(serverDataSenderThread, INFINITE);
			//CloseHandle(serverDataReceiverThread);
			break;
		}

		case RES_ERROR_CLOSE_CONNECT: 
		{
			printf("El cliente ha intentado cerrar la conexion pero la operacion no pudo realizarse correctamente.\n");
			break;
		}

		case RES_OK: 
		{
			printf("Se han recibido la siguiente cantidad de items: %i \n", cantItems);
			printf("%s", datos);			
			break;
		}									
	}
	return RES_OK;
}


DWORD WINAPI DataSenderThread (LPVOID lpParameter){

	CONEXION *pConexion = (CONEXION*)lpParameter;

	if (DataSender(pConexion) == RES_QUIT){		
		Sleep(SLEEPTIME);
		closeThread = 1;		
		trCerrarConexion(pConexion);	
	}

	printf("La conexion ha sido cerrada.\n");
	return RES_OK;
}


/********************************************************************************************** 
 * Parsea el string de entrada en el cual debe recbir un puerto ej: servidor.exe 5900         *
 * devuelve RES_OK si la cantidad de parametros es valida e ingreso un puerto valido          *
 * devuelve RES_ERROR_COMMAND_LINE si hay algun error al recibir o transformar los parametros *
 * *******************************************************************************************/

int parseCommandLine(int argc, char* argv[], int *port){
	if(argc!=2){
		printf("Error al ingresar los parametros de entrada");
		return RES_ERROR_COMMAND_LINE;
	}
	else{
		int size;
		int i;
		size=strlen(argv[1]);
		for(i=0;i<size;i++){
			if ((argv[1][i]<'0') || (argv[1][i]>'9')){
				printf("Error al ingresar un puerto de tipo erroneo");	
				return RES_ERROR_PORT_TYPE;
			}
		}
		(*port)=atoi(argv[1]);
		if (((*port) <=1023) || ((*port)>65535)){ /* Si esta fuera de rango.. */
			printf("Error al ingresar un puerto fuera del rango");
			return RES_ERROR_PORT_RANGE; 
		}
		return RES_OK;
	}
}
